package com.zoro.barn.business.service.pp.conf;

import com.zoro.barn.commons.db.autopage.BarnPagerProperties;
import com.zoro.barn.commons.db.autopage.PagingFeignRequestEncoder;
import com.zoro.barn.commons.db.autopage.PagingFeignResponseHandler;
import com.zoro.barn.commons.foundation.web.FeignResponseHandler;
import com.zoro.barn.commons.webcommons.feign.BarnRequestEncoder;
import com.zoro.barn.commons.webcommons.feign.BarnResponseEntityDecoder;
import feign.Feign;
import feign.Logger;
import feign.codec.Decoder;
import feign.codec.Encoder;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.feign.FeignDecorators;
import io.github.resilience4j.feign.Resilience4jFeign;
import io.github.resilience4j.retry.Retry;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.cloud.openfeign.support.AbstractFormWriter;
import org.springframework.cloud.openfeign.support.HttpMessageConverterCustomizer;
import org.springframework.context.annotation.Bean;

/**
 * @author zhaoxingwu
 */
@EnableConfigurationProperties(BarnPagerProperties.class)
public class FeignConfig extends FeignClientsConfiguration {

    private final BarnPagerProperties barnPagerProperties;


    public FeignConfig(BarnPagerProperties barnPagerProperties) {
        this.barnPagerProperties = barnPagerProperties;
    }

    @Bean
    public Decoder feignDecoder() {
        FeignResponseHandler handler = new PagingFeignResponseHandler(barnPagerProperties.getCurrent(),
                barnPagerProperties.getCount());
        BarnResponseEntityDecoder decoder = new BarnResponseEntityDecoder();
        decoder.addResponseHandler(handler);
        return decoder;
    }

    @Bean
    public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider,
                                ObjectProvider<HttpMessageConverterCustomizer> customizers) {
        Encoder delegate = super.feignEncoder(formWriterProvider, customizers);

        PagingFeignRequestEncoder barnEncoder = new PagingFeignRequestEncoder(this.barnPagerProperties.getCurrent(),
                this.barnPagerProperties.getPageSize());
        BarnRequestEncoder bean = new BarnRequestEncoder(delegate);
        bean.addRequestHandler(barnEncoder);
        return bean;
    }

    @Bean
    public Feign.Builder feignBuilder() {
        /*
        decorators 的设置顺序会影响接口的调用，
        decorators 会按设置的倒序起作用，
        如果使用注解形式，官方的默认顺序是 Retry ( CircuitBreaker ( RateLimiter ( TimeLimiter ( Bulkhead ( Function ) ) ) ) )，
        retry 会最后起 作用
         */

        FeignDecorators decorators = FeignDecorators.builder()
                // TODO 这个还要再好好理解一下，测试代码要加上try catch ,并打印结果
                .withRetry(Retry.ofDefaults("all"))
                .withCircuitBreaker(CircuitBreaker.ofDefaults("all"))
                .build();

        return Resilience4jFeign.builder(decorators);
    }

    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}
